package io.gitee.zhangbinhub.admin.log.controller

import cn.dev33.satoken.annotation.SaCheckPermission
import cn.dev33.satoken.annotation.SaCheckRole
import io.gitee.zhangbinhub.acp.boot.exceptions.WebException
import io.gitee.zhangbinhub.acp.boot.log.LogAdapter
import io.gitee.zhangbinhub.acp.core.common.CalendarTools
import io.gitee.zhangbinhub.acp.core.common.CommonTools
import io.gitee.zhangbinhub.admin.common.constant.ModuleFuncCode
import io.gitee.zhangbinhub.admin.common.constant.RoleCode
import io.gitee.zhangbinhub.admin.common.vo.CustomerQueryPageVo
import io.gitee.zhangbinhub.admin.log.base.BaseLogEntity
import io.gitee.zhangbinhub.admin.log.constant.LogApi
import io.gitee.zhangbinhub.admin.log.constant.LogConstant
import io.gitee.zhangbinhub.admin.log.po.FileDownLoadPo
import io.gitee.zhangbinhub.admin.log.po.LogQueryPo
import io.gitee.zhangbinhub.admin.log.service.LogFileService
import io.gitee.zhangbinhub.admin.log.service.LogService
import io.gitee.zhangbinhub.admin.log.vo.LoginLogVo
import io.gitee.zhangbinhub.admin.resource.server.base.BaseResourceServerController
import io.gitee.zhangbinhub.admin.resource.server.nami.client.CommonOauthServer
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
import org.bouncycastle.util.encoders.Base64
import org.noear.snack4.ONode
import org.noear.solon.annotation.Body
import org.noear.solon.annotation.Controller
import org.noear.solon.annotation.Mapping
import org.noear.solon.annotation.Param
import org.noear.solon.core.handle.Context
import org.noear.solon.core.handle.MethodType
import org.noear.solon.core.util.MimeType
import org.noear.solon.validation.annotation.NotBlank
import org.noear.solon.validation.annotation.NotNull
import org.noear.solon.validation.annotation.Valid
import org.noear.solon.validation.annotation.Validated
import java.io.File

/**
 * @since JDK 11
 */
@Valid
@Controller
@Api("日志信息")
open class LogController(
    private val logAdapter: LogAdapter,
    private val logFileService: LogFileService,
    private val logService: LogService,
    private val commonOauthServer: CommonOauthServer
) : BaseResourceServerController(logAdapter) {
    @ApiOperation("获取各应用过去3个月的登录次数统计")
    @SaCheckPermission(ModuleFuncCode.sysMonitor, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.GET],
        value = LogApi.basePath + LogApi.loginInfo,
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun findLoginLog(): List<LoginLogVo> =
        CalendarTools.getNowDateTime().withTimeAtStartOfDay().minusMonths(LogConstant.LOGIN_LOG_STATISTICS_MAX_MONTH)
            .let {
                logService.loginStatistics(it.millis)
            }

    @ApiOperation("查询路由日志列表")
    @SaCheckPermission(ModuleFuncCode.sysMonitor, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.POST],
        value = LogApi.basePath + LogApi.gateWayRouteLog,
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun queryRouteLog(@Body @Validated logQueryPo: LogQueryPo): CustomerQueryPageVo<out BaseLogEntity> =
        logService.doQueryRouteLog(logQueryPo)

    @ApiOperation("查询操作日志列表")
    @SaCheckPermission(ModuleFuncCode.sysMonitor, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.POST],
        value = LogApi.basePath + LogApi.operateLog,
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun queryOperateLog(@Body @Validated logQueryPo: LogQueryPo): CustomerQueryPageVo<out BaseLogEntity> =
        logService.doQueryOperateLog(logQueryPo)

    @ApiOperation("查询登录日志列表")
    @SaCheckPermission(ModuleFuncCode.sysMonitor, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.POST],
        value = LogApi.basePath + LogApi.loginLog,
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun queryLoginLog(@Body @Validated logQueryPo: LogQueryPo): CustomerQueryPageVo<out BaseLogEntity> =
        logService.doQueryLoginLog(logQueryPo)

    @ApiOperation("查询指定日期范围的日志备份文件")
    @SaCheckRole(RoleCode.SUPER)
    @Mapping(
        method = [MethodType.POST], value = LogApi.basePath + LogApi.logFile, produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun queryFile(
        @ApiParam(name = "开始日期", required = true, example = "0")
        @NotNull(message = "开始日期不能为空")
        @Param(name = "startDate")
        startDate: Long,
        @ApiParam(name = "结束日期", required = true, example = "0")
        @NotNull(message = "结束日期不能为空")
        @Param(name = "endDate")
        endDate: Long
    ): List<String> =
        try {
            val start = longToDate(startDate)
            val end = longToDate(endDate)
            val nowDay = longToDate(CalendarTools.getNowDateTime().toDate().time)
            if (start > end) {
                throw WebException("开始日期不能大于结束日期")
            }
            if (end >= nowDay) {
                throw WebException("结束日期必须早于当前")
            }
            logFileService.fileList(
                CalendarTools.getDateTimeString(start, CalendarTools.DATE_FORMAT),
                CalendarTools.getDateTimeString(end, CalendarTools.DATE_FORMAT)
            )
        } catch (e: Exception) {
            logAdapter.error(e.message, e)
            throw WebException(e.message)
        }

    @ApiOperation("日志文件下载")
    @Mapping(
        method = [MethodType.GET], value = LogApi.basePath + LogApi.logFile, produces = MimeType.ALL_VALUE
    )
    @Throws(WebException::class)
    fun downloadFile(
        context: Context,
        @ApiParam(name = "文件内容", required = true)
        @NotBlank(message = "文件内容不能为空")
        @Param(name = "params") params: String
    ) {
        val fileDownLoadPo: FileDownLoadPo = ONode.deserialize(params, FileDownLoadPo::class.java)
        if (CommonTools.isNullStr(fileDownLoadPo.fileName)) {
            throw WebException("文件名称不能为空")
        }
        val fileName =
            String(Base64.decode(fileDownLoadPo.fileName), CommonTools.getDefaultCharset()).replace(
                "/",
                File.separator
            ).replace("\\", File.separator)
        logFileService.doDownLoadFile(context, fileName)
    }
}
